# -*- coding: utf-8 -*-
"""
@Time    : 2024/8/27 15:01 
@Author  : ZhangShenao 
@File    : 1.ReAct模式的Agent.py 
@Desc    : 实现ReAct模式的Agent

在LangChain中,Agent是一个核心概念,它代表了一个能够利用LLM和其他工具来解决复杂任务的系统
Agent设计的目的是为了处理那些LLM可能无法直接解决的问题
尤其是当这些任务涉及到多个步骤或者需要外部数据源的情况

Agent的核心工作流程:
1. 输入理解: Agent首先解析用户输入,理解其意图和需求
2. 计划定制: 基于对输入的理解,Agent 会定制一个执行计划,决定使用哪些工具,以及工具的执行顺序
3. 工具调用: Agent按照计划调用相应的工具,执行必要的操作
4. 结果整合: 收集所有工具返回的结果,进行整合和解析,形成最终的输出
5. 反馈循环: 如果任务没有完成或者需要进一步的消息,Agent可以迭代上述过程直到满足条件为止

对于一个Agent来说,其组成主要包括以下三个模块:
1. Tools: Agent可以访问的工具集,每个工具通常执行一个特定的功能
2. Executor: 负责执行Agent计划的执行器
3. Prompt Templates: 指导Agent如何理解和处理输入的模板,可以定制化以适应不同任务

ReACT=Reason+Action,即推理与行动
目前绝大部分Agent架构都是在ReACT架构上衍生出来的
该架构最早是Yao等人在2022年发布的论文中首次被提出
论文参考地址: https://arxiv.org/pdf/2210.03629

ReACT prompt文档: https://smith.langchain.com/hub/hwchase17/react

ReACT模式的缺陷:
1. 由于LLM输出的不稳定性,可能生成的内容不满足ReACT Prompt的格式规范,导致解析异常
2. 针对中文环境,需要将Prompt及对应的OutputParser全部转换成中文,涉及较大的工作量
"""
import os

import dotenv
from langchain import hub
from langchain.agents import create_react_agent, AgentExecutor
from langchain_core.tools import render_text_description_and_args
from langchain_openai import ChatOpenAI

from google_serper_tool import create_google_serper_tool

# 加载环境变量
dotenv.load_dotenv()

# 创建工具列表
tools = [create_google_serper_tool()]

# 从LangSmith平台拉取ReACT模式的Prompt
prompt = hub.pull("hwchase17/react")

# 创建LLM
llm = ChatOpenAI(model="gpt-4o", openai_api_base=os.getenv("OPENAI_API_BASE"))

# 创建ReACT模式的Agent
react_agent = create_react_agent(
    llm=llm,  # 指定LLM
    tools=tools,  # 指定工具列表
    prompt=prompt,  # 指定prompt
    tools_renderer=render_text_description_and_args,  # 指定工具信息渲染函数,包含工具描述和参数信息
)

# 创建Agent执行器
executor = AgentExecutor(
    agent=react_agent,  # 指定Agent
    tools=tools,  # 指定工具列表
    verbose=True,  # 打印中间过程
)

# 调用执行器,开始执行Agent
result = executor.invoke({"input": "今年奥运会乒乓球男子单打冠军是谁？"})
print(result)
